/* -*- mode: c; indent-tabs-mode: nil; c-indent-level: 4; -*-

 * $Id: image.c,v 1.5 2004/03/06 17:56:36 chrish Exp $
 *
 * Viewer - a part of Plucker, the open-source, open-format ebook system
 * Copyright (c) 2002, Bill Janssen
 * 
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */

#include <gtk/gtk.h>
#include <gdk-pixbuf/gdk-pixdata.h>
#include <stdlib.h>             /* for exit() */
#include <stdio.h>
#include <unpluck.h>
#include <sys/stat.h>
#include <string.h>

/* GdkPixbuf RGBA C-Source image dump 1-byte-run-length-encoded */

static const GdkPixdata again_icon_pixdata = {
    0x47646b50,                 /* Pixbuf magic: 'GdkP' */
    24 + 214,                   /* header length + pixel_data length */
    0x2010002,                  /* pixdata_type */
    52,                         /* rowstride */
    13,                         /* width */
    13,                         /* height */
    /* pixel_data: */
    "\244\0\377\0\0\1" "3f\231\377\213\0\377\0\0\3" "3f\231\377\0\377\0\0"
    "3" "f\231\377\211\0\377\0\0\1"
    "3f\231\377\207\0\377\0\0\2053f\231\377\205" "\0\377\0\0\3"
    "3f\231\377\0\377\0\0" "3f\231\377\204\314\314\377\377\1"
    "3f\231\377\206\0\377\0\0\1" "3f\231\377\206\314\314\377\377\3"
    "3f\231" "\377\0\377\0\0\314\314\314\377\203\0\377\0\0\1"
    "3f\231\377\204\314\314"
    "\377\377\6\377\377\377\377\314\314\377\3773f\231\377\314\314\314\377"
    "\0\377\0\0\314\314\314\377\202\0\377\0\0\1"
    "3f\231\377\202\314\314\377"
    "\377\202\377\377\377\377\202\314\314\377\377\1"
    "3f\231\377\206\0\377" "\0\0\1" "3f\231\377\204\314\314\377\377\1"
    "3f\231\377\210\0\377\0\0\204"
    "3f\231\377\1\314\314\314\377\222\0\377\0\0",
};


/* GdkPixbuf RGBA C-Source image dump 1-byte-run-length-encoded */

static const GdkPixdata autodecr_icon_pixdata = {
    0x47646b50,                 /* Pixbuf magic: 'GdkP' */
    24 + 170,                   /* header length + pixel_data length */
    0x2010002,                  /* pixdata_type */
    40,                         /* rowstride */
    10,                         /* width */
    13,                         /* height */
    /* pixel_data: */
    "\216\0\377\0\0\206\231\231\314\377\203\0\377\0\0\1\231\231\314\377\206"
    "\377\377\377\377\202\0\377\0\0\1\231\231\314\377\207\377\377\377\377"
    "\202\0\377\0\0\1\231\231\314\377\207\377\377\377\377\202\0\377\0\0\1"
    "\231\231\314\377\207\377\377\377\377\202\0\377\0\0\1\231\231\314\377"
    "\202\377\377\377\377\2033f\231\377\202\377\377\377\377\202\0\377\0\0"
    "\1\231\231\314\377\207\377\377\377\377\202\0\377\0\0\1\231\231\314\377"
    "\207\377\377\377\377\202\0\377\0\0\1\231\231\314\377\207\377\377\377"
    "\377\203\0\377\0\0\1\231\231\314\377\206\377\377\377\377\204\0\377\0"
    "\0\206\231\231\314\377\212\0\377\0\0",
};


/* GdkPixbuf RGBA C-Source image dump 1-byte-run-length-encoded */

static const GdkPixdata autoincr_icon_pixdata = {
    0x47646b50,                 /* Pixbuf magic: 'GdkP' */
    24 + 190,                   /* header length + pixel_data length */
    0x2010002,                  /* pixdata_type */
    40,                         /* rowstride */
    10,                         /* width */
    13,                         /* height */
    /* pixel_data: */
    "\212\0\377\0\0\206\231\231\314\377\204\0\377\0\0\206\377\377\377\377"
    "\1\231\231\314\377\203\0\377\0\0\207\377\377\377\377\1\231\231\314\377"
    "\202\0\377\0\0\207\377\377\377\377\1\231\231\314\377\202\0\377\0\0\203"
    "\377\377\377\377\1"
    "3f\231\377\203\377\377\377\377\1\231\231\314\377"
    "\202\0\377\0\0\202\377\377\377\377\2033f\231\377\202\377\377\377\377"
    "\1\231\231\314\377\202\0\377\0\0\203\377\377\377\377\1"
    "3f\231\377\203"
    "\377\377\377\377\1\231\231\314\377\202\0\377\0\0\207\377\377\377\377"
    "\1\231\231\314\377\202\0\377\0\0\207\377\377\377\377\1\231\231\314\377"
    "\202\0\377\0\0\206\377\377\377\377\1\231\231\314\377\203\0\377\0\0\206"
    "\231\231\314\377\216\0\377\0\0",
};


/* GdkPixbuf RGBA C-Source image dump 1-byte-run-length-encoded */

static const GdkPixdata autostart_icon_pixdata = {
    0x47646b50,                 /* Pixbuf magic: 'GdkP' */
    24 + 145,                   /* header length + pixel_data length */
    0x2010002,                  /* pixdata_type */
    52,                         /* rowstride */
    13,                         /* width */
    13,                         /* height */
    /* pixel_data: */
    "\215\0\377\0\0\216\231\231\314\377\213\377\377\377\377\202\231\231\314"
    "\377\213\377\377\377\377\202\231\231\314\377\206\377\377\377\377\1" "3"
    "f\231\377\204\377\377\377\377\202\231\231\314\377\206\377\377\377\377"
    "\2023f\231\377\203\377\377\377\377\202\231\231\314\377\1\377\377\377"
    "\377\2103f\231\377\202\377\377\377\377\202\231\231\314\377\1\377\377"
    "\377\377\2113f\231\377\1\377\377\377\377\202\231\231\314\377\213\377"
    "\377\377\377\202\231\231\314\377\213\377\377\377\377\202\231\231\314"
    "\377\213\377\377\377\377\216\231\231\314\377\215\0\377\0\0",
};


/* GdkPixbuf RGBA C-Source image dump 1-byte-run-length-encoded */

static const GdkPixdata autostop_icon_pixdata = {
    0x47646b50,                 /* Pixbuf magic: 'GdkP' */
    24 + 155,                   /* header length + pixel_data length */
    0x2010002,                  /* pixdata_type */
    52,                         /* rowstride */
    13,                         /* width */
    13,                         /* height */
    /* pixel_data: */
    "\215\0\377\0\0\216\231\231\314\377\213\377\377\377\377\202\231\231\314"
    "\377\213\377\377\377\377\202\231\231\314\377\203\377\377\377\377\205"
    "3f\231\377\203\377\377\377\377\202\231\231\314\377\203\377\377\377\377"
    "\2053f\231\377\203\377\377\377\377\202\231\231\314\377\203\377\377\377"
    "\377\2053f\231\377\203\377\377\377\377\202\231\231\314\377\203\377\377"
    "\377\377\2053f\231\377\203\377\377\377\377\202\231\231\314\377\203\377"
    "\377\377\377\2053f\231\377\203\377\377\377\377\202\231\231\314\377\213"
    "\377\377\377\377\202\231\231\314\377\213\377\377\377\377\216\231\231"
    "\314\377\215\0\377\0\0",
};


/* GdkPixbuf RGBA C-Source image dump 1-byte-run-length-encoded */

static const GdkPixdata bar_icon_pixdata = {
    0x47646b50,                 /* Pixbuf magic: 'GdkP' */
    24 + 15,                    /* header length + pixel_data length */
    0x2010002,                  /* pixdata_type */
    640,                        /* rowstride */
    160,                        /* width */
    2,                          /* height */
    /* pixel_data: */
    "\37733f\0\37733f\0\30233f\0",
};


/* GdkPixbuf RGBA C-Source image dump 1-byte-run-length-encoded */

static const GdkPixdata bookmark_icon_pixdata = {
    0x47646b50,                 /* Pixbuf magic: 'GdkP' */
    24 + 232,                   /* header length + pixel_data length */
    0x2010002,                  /* pixdata_type */
    52,                         /* rowstride */
    13,                         /* width */
    13,                         /* height */
    /* pixel_data: */
    "\211\0\377\0\0\1\314\314\377\377\213\0\377\0\0\3\314\314\377\377\231"
    "\231\314\3773f\231\377\211\0\377\0\0\1\314\314\377\377\203\231\231\314"
    "\377\1"
    "3f\231\377\207\0\377\0\0\1\314\314\377\377\205\231\231\314\377"
    "\1"
    "3f\231\377\205\0\377\0\0\1\314\314\377\377\205\231\231\314\377\1"
    "3f\231\377\205\0\377\0\0\1\314\314\377\377\205\231\231\314\377\1"
    "3f"
    "\231\377\205\0\377\0\0\1\314\314\377\377\205\231\231\314\377\1"
    "3f\231"
    "\377\205\0\377\0\0\1\314\314\377\377\205\231\231\314\377\1"
    "3f\231\377" "\205\0\377\0\0\2033f\231\377\203\231\231\314\377\1"
    "3f\231\377\205\314"
    "\314\314\377\204\0\377\0\0\202\231\231\314\377\1"
    "3f\231\377\205\314"
    "\314\314\377\205\0\377\0\0\2\231\231\314\3773f\231\377\204\314\314\314"
    "\377\207\0\377\0\0\1"
    "3f\231\377\203\314\314\314\377\222\0\377\0\0",
};


/* GdkPixbuf RGBA C-Source image dump 1-byte-run-length-encoded */

static const GdkPixdata bubble_icon_pixdata = {
    0x47646b50,                 /* Pixbuf magic: 'GdkP' */
    24 + 155,                   /* header length + pixel_data length */
    0x2010002,                  /* pixdata_type */
    52,                         /* rowstride */
    13,                         /* width */
    13,                         /* height */
    /* pixel_data: */
    "\223\0\377\0\0\2053f\231\377\207\0\377\0\0\1" "3f\231\377\205\314\314"
    "\377\377\1" "3f\231\377\205\0\377\0\0\1"
    "3f\231\377\207\314\314\377\377" "\1" "3f\231\377\204\0\377\0\0\1"
    "3f\231\377\207\314\314\377\377\1" "3f" "\231\377\205\0\377\0\0\1"
    "3f\231\377\205\314\314\377\377\1" "3f\231\377"
    "\207\0\377\0\0\2053f\231\377\205\0\377\0\0\2023f\231\377\212\0\377\0"
    "\0\1" "3f\231\377\202\314\314\377\377\1"
    "3f\231\377\212\0\377\0\0\202" "3f\231\377\226\0\377\0\0\1"
    "3f\231\377\230\0\377\0\0",
};


/* GdkPixbuf RGBA C-Source image dump 1-byte-run-length-encoded */

static const GdkPixdata chicken_icon_pixdata = {
    0x47646b50,                 /* Pixbuf magic: 'GdkP' */
    24 + 2670,                  /* header length + pixel_data length */
    0x2010002,                  /* pixdata_type */
    592,                        /* rowstride */
    148,                        /* width */
    47,                         /* height */
    /* pixel_data: */
    "\375\0\377\0\0\202\377\0" "3\377\377\0\377\0\0\222\0\377\0\0\1\377\0"
    "3" "\377\377\0\377\0\0\223\0\377\0\0\1\377\0"
    "3\377\275\0\377\0\0\204\0\0" "\0\377\322\0\377\0\0\1\377\0"
    "3\377\301\0\377\0\0\202\0\0\0\377\317\0" "\377\0\0\1\377\0"
    "3\377\304\0\377\0\0\1\0\0\0\377\316\0\377\0\0\1\377" "\0"
    "3\377\305\0\377\0\0\1\0\0\0\377\315\0\377\0\0\1\377\0" "3\377\305"
    "\0\377\0\0\1\0\0\0\377\314\0\377\0\0\1\377\0"
    "3\377\307\0\377\0\0\1\0"
    "\0\0\377\202\0\377\0\0\1\0\0\0\377\302\0\377\0\0\1\377\0"
    "3\377\205\0" "\377\0\0\1\377\0"
    "3\377\307\0\377\0\0\1\0\0\0\377\203\0\377\0\0\1\0\0"
    "\0\377\302\0\377\0\0\1\377\0" "3\377\204\0\377\0\0\1\377\0"
    "3\377\307"
    "\0\377\0\0\1\0\0\0\377\203\0\377\0\0\1\0\0\0\377\303\0\377\0\0\1\377"
    "\0" "3\377\202\0\377\0\0\1\377\0" "3\377\203\0\377\0\0\1\377\0"
    "3\377\272"
    "\0\377\0\0\203\0\0\0\377\210\0\377\0\0\1\0\0\0\377\202\0\377\0\0\1\0"
    "\0\0\377\304\0\377\0\0\3\377\0" "3\377\0\377\0\0\377\0"
    "3\377\203\0\377" "\0\0\1\377\0"
    "3\377\270\0\377\0\0\202\0\0\0\377\203\0\377\0\0\203\0\0"
    "\0\377\205\0\377\0\0\1\0\0\0\377\202\0\377\0\0\1\0\0\0\377\304\0\377"
    "\0\0\3\377\0" "3\377\0\377\0\0\377\0"
    "3\377\202\0\377\0\0\1\377\0" "3\377"
    "\301\0\377\0\0\202\0\0\0\377\203\0\377\0\0\3\0\0\0\377\0\377\0\0\0\0"
    "\0\377\306\0\377\0\0\202\377\0" "3\377\2\0\377\0\0\377\0"
    "3\377\304\0"
    "\377\0\0\1\0\0\0\377\202\0\377\0\0\3\0\0\0\377\0\377\0\0\0\0\0\377\202"
    "\0\377\0\0\232\0\0\0\377\252\0\377\0\0\202\377\0"
    "3\377\3\0\377\0\0\377" "\0"
    "3\377\0\377\0\0\205\0\0\0\377\277\0\377\0\0\1\0\0\0\377\202\0\377"
    "\0\0\2\0\0\0\377\0\377\0\0\202\0\0\0\377\232\377\377\0\377\204\0\0\0"
    "\377\246\0\377\0\0\203\377\0"
    "3\377\1\377\377\377\377\202\0\0\0\377\204"
    "\377\377\377\377\202\0\0\0\377\276\0\377\0\0\204\0\0\0\377\240\377\377"
    "\0\377\204\0\0\0\377\242\0\377\0\0\202\377\0"
    "3\377\202\0\0\0\377\207"
    "\377\377\377\377\203\0\0\0\377\273\0\377\0\0\1\0\0\0\377\250\377\377"
    "\0\377\203\0\0\0\377\235\0\377\0\0\202\0\0\0\377\1\377\377\0\377\202"
    "\0\0\0\377\211\377\377\377\377\2\0\0\0\377\377\377\377\377\202\0\0\0"
    "\377\270\0\377\0\0\1\0\0\0\377\254\377\377\0\377\202\0\0\0\377\232\0"
    "\377\0\0\1\0\0\0\377\203\377\377\0\377\1\0\0\0\377\212\377\377\377\377"
    "\1\0\0\0\377\203\377\377\377\377\1\0\0\0\377\266\0\377\0\0\1\0\0\0\377"
    "\203\377\377\0\377\207\0\0\0\377\245\377\377\0\377\202\0\0\0\377\227"
    "\0\377\0\0\1\0\0\0\377\204\377\377\0\377\1\0\0\0\377\210\377\377\377"
    "\377\1\377\0"
    "3\377\202\377\377\377\377\1\0\0\0\377\203\377\377\377\377"
    "\1\0\0\0\377\264\0\377\0\0\205\0\0\0\377\256\377\377\0\377\202\0\0\0"
    "\377\224\0\377\0\0\1\0\0\0\377\204\377\377\0\377\1\0\0\0\377\211\377"
    "\377\377\377\1\377\0"
    "3\377\202\377\377\377\377\5\0\0\0\377\377\377\377" "\377\377\0"
    "3\377\377\377\377\377\0\0\0\377\262\0\377\0\0\202\0\0\0\377"
    "\265\377\377\0\377\1\0\0\0\377\223\0\377\0\0\1\0\0\0\377\204\377\377"
    "\0\377\1\0\0\0\377\214\377\377\377\377\1\0\0\0\377\203\377\377\377\377"
    "\1\0\0\0\377\261\0\377\0\0\1\0\0\0\377\270\377\377\0\377\202\0\0\0\377"
    "\220\0\377\0\0\1\0\0\0\377\205\377\377\0\377\1\0\0\0\377\214\377\377"
    "\377\377\1\0\0\0\377\203\377\377\377\377\1\0\0\0\377\260\0\377\0\0\1"
    "\0\0\0\377\273\377\377\0\377\1\0\0\0\377\217\0\377\0\0\1\0\0\0\377\206"
    "\377\377\0\377\1\0\0\0\377\213\377\377\377\377\205\0\0\0\377\257\0\377"
    "\0\0\1\0\0\0\377\275\377\377\0\377\202\0\0\0\377\214\0\377\0\0\1\0\0"
    "\0\377\207\377\377\0\377\1\0\0\0\377\212\377\377\377\377\1\0\0\0\377"
    "\204\377\377\231\377\202\0\0\0\377\255\0\377\0\0\1\0\0\0\377\300\377"
    "\377\0\377\207\0\0\0\377\203\0\377\0\0\202\0\0\0\377\206\377\377\0\377"
    "\1\0\0\0\377\202\377\377\0\377\1\0\0\0\377\210\377\377\377\377\1\0\0"
    "\0\377\207\377\377\231\377\1\0\0\0\377\253\0\377\0\0\1\0\0\0\377\310"
    "\377\377\0\377\203\0\0\0\377\210\377\377\0\377\1\0\0\0\377\203\377\377"
    "\0\377\203\0\0\0\377\203\377\377\377\377\202\0\0\0\377\211\377\377\231"
    "\377\202\0\0\0\377\247\0\377\0\0\202\0\0\0\377\263\377\377\0\377\1\0"
    "\0\0\377\241\377\377\0\377\1\0\0\0\377\205\377\377\0\377\203\0\0\0\377"
    "\207\377\377\231\377\3\0\0\0\377\377\377\231\377\0\0\0\377\203\377\377"
    "\231\377\1\0\0\0\377\211\0\377\0\0\207\0\0\0\377\225\0\377\0\0\1\0\0"
    "\0\377\264\377\377\0\377\1\0\0\0\377\212\377\377\0\377\1\0\0\0\377\230"
    "\377\377\0\377\1\0\0\0\377\206\377\377\0\377\1\0\0\0\377\216\377\377"
    "\231\377\202\0\0\0\377\206\0\377\0\0\1\0\0\0\377\207\377\0"
    "3\377\203"
    "\0\0\0\377\214\0\377\0\0\206\0\0\0\377\265\377\377\0\377\1\0\0\0\377"
    "\212\377\377\0\377\1\0\0\0\377\211\377\377\0\377\205\0\0\0\377\220\377"
    "\377\0\377\1\0\0\0\377\221\377\377\231\377\1\0\0\0\377\206\0\377\0\0"
    "\205\0\0\0\377\205\377\0"
    "3\377\204\0\0\0\377\202\0\377\0\0\206\0\0\0" "\377\206\377\0"
    "3\377\1\0\0\0\377\226\377\377\0\377\1\0\0\0\377\235\377"
    "\377\0\377\1\0\0\0\377\211\377\377\0\377\1\0\0\0\377\204\377\377\0\377"
    "\206\0\0\0\377\205\0\377\0\0\203\0\0\0\377\215\377\377\0\377\1\0\0\0"
    "\377\222\377\377\231\377\1\0\0\0\377\212\0\377\0\0\1\0\0\0\377\210\377"
    "\0" "3\377\202\0\0\0\377\207\377\0"
    "3\377\206\0\0\0\377\207\377\377\0"
    "\377\207\0\0\0\377\206\377\377\0\377\202\0\0\0\377\234\377\377\0\377"
    "\3\0\0\0\377\377\377\0\377\0\0\0\377\211\377\377\0\377\1\0\0\0\377\203"
    "\377\377\0\377\1\0\0\0\377\206\377\377\0\377\202\0\0\0\377\206\0\377"
    "\0\0\202\0\0\0\377\213\377\377\0\377\1\0\0\0\377\223\377\377\231\377"
    "\1\0\0\0\377\204\0\377\0\0\214\0\0\0\377\204\377\0"
    "3\377\207\0\0\0\377" "\205\377\0"
    "3\377\210\0\0\0\377\207\377\377\0\377\206\0\0\0\377\237\377"
    "\377\0\377\202\0\0\0\377\212\377\377\0\377\3\0\0\0\377\377\377\0\377"
    "\0\0\0\377\211\377\377\0\377\202\0\0\0\377\206\0\377\0\0\202\0\0\0\377"
    "\211\377\377\0\377\1\0\0\0\377\203\377\377\231\377\205\0\0\0\377\214"
    "\377\377\231\377\1\0\0\0\377\202\0\377\0\0\1\0\0\0\377\212\377\0"
    "3\377" "\2\0\0\0\377\377\0" "3\377\202\0\0\0\377\212\377\0"
    "3\377\203\0\0\0\377" "\202\377\0"
    "3\377\1\0\0\0\377\264\377\377\0\377\1\0\0\0\377\212\377\377"
    "\0\377\202\0\0\0\377\213\377\377\0\377\202\0\0\0\377\206\0\377\0\0\202"
    "\0\0\0\377\207\377\377\0\377\1\0\0\0\377\210\377\377\231\377\215\0\0"
    "\0\377\203\0\377\0\0\205\0\0\0\377\203\377\0"
    "3\377\202\0\0\0\377\204" "\377\0" "3\377\212\0\0\0\377\204\377\0"
    "3\377\2\0\0\0\377\0\377\0\0\202"
    "\0\0\0\377\204\377\377\0\377\221\0\0\0\377\220\377\377\0\377\204\0\0"
    "\0\377\210\377\377\0\377\202\0\0\0\377\214\377\377\0\377\1\0\0\0\377"
    "\204\377\377\0\377\205\0\0\0\377\203\377\377\0\377\1\0\0\0\377\207\0"
    "\377\0\0\202\0\0\0\377\206\377\377\0\377\1\0\0\0\377\215\377\377\231"
    "\377\1\0\0\0\377\216\0\377\0\0\203\0\0\0\377\221\377\0"
    "3\377\203\0\0"
    "\0\377\204\0\377\0\0\204\0\0\0\377\221\0\377\0\0\220\0\0\0\377\204\0"
    "\377\0\0\210\0\0\0\377\202\0\377\0\0\1\0\0\0\377\214\377\377\0\377\204"
    "\0\0\0\377\205\0\377\0\0\203\0\0\0\377\212\0\377\0\0\202\0\0\0\377\205"
    "\377\377\0\377\1\0\0\0\377\212\377\377\231\377\202\0\0\0\377\215\0\377"
    "\0\0\202\0\0\0\377\206\377\0" "3\377\206\0\0\0\377\203\377\0"
    "3\377\205"
    "\0\0\0\377\273\0\377\0\0\1\0\0\0\377\214\377\377\0\377\202\0\0\0\377"
    "\225\0\377\0\0\203\0\0\0\377\203\377\377\0\377\1\0\0\0\377\207\377\377"
    "\231\377\202\0\0\0\377\215\0\377\0\0\202\0\0\0\377\205\377\0"
    "3\377\203" "\0\0\0\377\202\0\377\0\0\1\0\0\0\377\204\377\0"
    "3\377\203\0\0\0\377\300"
    "\0\377\0\0\202\0\0\0\377\214\377\377\0\377\202\0\0\0\377\226\0\377\0"
    "\0\213\0\0\0\377\216\0\377\0\0\1\0\0\0\377\204\377\0"
    "3\377\203\0\0\0" "\377\203\0\377\0\0\202\0\0\0\377\203\377\0"
    "3\377\202\0\0\0\377\305\0"
    "\377\0\0\202\0\0\0\377\214\377\377\0\377\1\0\0\0\377\257\0\377\0\0\204"
    "\0\0\0\377\205\0\377\0\0\1\0\0\0\377\203\377\0"
    "3\377\202\0\0\0\377\311"
    "\0\377\0\0\205\0\0\0\377\210\377\377\0\377\1\0\0\0\377\265\0\377\0\0"
    "\202\0\0\0\377\203\377\0"
    "3\377\1\0\0\0\377\315\0\377\0\0\202\0\0\0\377"
    "\211\377\377\0\377\1\0\0\0\377\264\0\377\0\0\1\0\0\0\377\203\377\0"
    "3"
    "\377\202\0\0\0\377\315\0\377\0\0\1\0\0\0\377\212\377\377\0\377\1\0\0"
    "\0\377\264\0\377\0\0\1\0\0\0\377\202\377\0"
    "3\377\202\0\0\0\377\316\0"
    "\377\0\0\1\0\0\0\377\211\377\377\0\377\202\0\0\0\377\266\0\377\0\0\202"
    "\0\0\0\377\316\0\377\0\0\202\0\0\0\377\207\377\377\0\377\203\0\0\0\377"
    "\377\0\377\0\0\210\0\377\0\0\1\0\0\0\377\206\377\377\0\377\203\0\0\0"
    "\377\377\0\377\0\0\212\0\377\0\0\1\0\0\0\377\203\377\377\0\377\204\0"
    "\0\0\377\377\0\377\0\0\214\0\377\0\0\205\0\0\0\377\270\0\377\0\0",
};


/* GdkPixbuf RGBA C-Source image dump 1-byte-run-length-encoded */

static const GdkPixdata find_icon_pixdata = {
    0x47646b50,                 /* Pixbuf magic: 'GdkP' */
    24 + 194,                   /* header length + pixel_data length */
    0x2010002,                  /* pixdata_type */
    44,                         /* rowstride */
    11,                         /* width */
    13,                         /* height */
    /* pixel_data: */
    "\235\0\377\0\0\1" "3f\231\377\211\0\377\0\0\3" "3f\231\377\0\377\0\0"
    "3" "f\231\377\207\0\377\0\0\1"
    "3f\231\377\211\0\377\0\0\2043f\231\377\206" "\0\377\0\0\1"
    "3f\231\377\204\314\314\377\377\3" "3f\231\377\0\377\0\0"
    "3f\231\377\202\0\377\0\0\1" "3f\231\377\206\314\314\377\377\1"
    "3f\231" "\377\203\0\377\0\0\1"
    "3f\231\377\204\314\314\377\377\3\377\377\377\377"
    "\314\314\377\3773f\231\377\203\0\377\0\0\1"
    "3f\231\377\202\314\314\377"
    "\377\202\377\377\377\377\202\314\314\377\377\1"
    "3f\231\377\204\0\377" "\0\0\1" "3f\231\377\204\314\314\377\377\1"
    "3f\231\377\206\0\377\0\0\204"
    "3f\231\377\1\314\314\314\377\215\0\377\0\0",
};


/* GdkPixbuf RGBA C-Source image dump 1-byte-run-length-encoded */

static const GdkPixdata home_icon_pixdata = {
    0x47646b50,                 /* Pixbuf magic: 'GdkP' */
    24 + 362,                   /* header length + pixel_data length */
    0x2010002,                  /* pixdata_type */
    52,                         /* rowstride */
    13,                         /* width */
    13,                         /* height */
    /* pixel_data: */
    "\223\0\377\0\0\203\231\231\314\377\2\314\314\377\377\231\231\314\377"
    "\207\0\377\0\0\1\231\231\314\377\2033f\231\377\2\314\314\377\377\231"
    "\231\314\377\206\0\377\0\0\3\231\231\314\37733f\377\231\231\314\377\202"
    "3f\231\377\2\314\314\377\377\231\231\314\377\205\0\377\0\0\5\231\231"
    "\314\37733f\377\231\231\314\377\314\314\377\377\231\231\314\377\2023"
    "f\231\377\202\231\231\314\377\203\0\377\0\0\3\231\231\314\37733f\377"
    "\231\231\314\377\203\314\314\377\377\1\231\231\314\377\2033f\231\377"
    "\5\231\231\314\377\0\377\0\0\231\231\314\37733f\377\231\231\314\377\205"
    "\314\314\377\377\1\231\231\314\377\2033f\231\377\3\0\377\0\0\314\314"
    "\377\377\231\231\314\377\202\314\314\377\377\202\231\231\314\377\202"
    "\314\314\377\377\3\231\231\314\37733f\3773f\231\377\204\0\377\0\0\202"
    "\314\314\377\377\2\231\231\314\3773f\231\377\202\314\314\377\377\1\231"
    "\231\314\377\20233f\377\204\0\377\0\0\202\314\314\377\377\2\231\231\314"
    "\3773f\231\377\202\314\314\377\377\1\231\231\314\377\2023f\231\377\204"
    "\0\377\0\0\202\314\314\377\377\2\231\231\314\3773f\231\377\202\314\314"
    "\377\377\202\231\231\314\377\1\314\314\314\377\204\0\377\0\0\202\314"
    "\314\377\377\2\231\231\314\3773f\231\377\202\314\314\377\377\1\231\231"
    "\314\377\203\314\314\314\377\215\0\377\0\0",
};


/* GdkPixbuf RGBA C-Source image dump 1-byte-run-length-encoded */

static const GdkPixdata hourglass_icon_pixdata = {
    0x47646b50,                 /* Pixbuf magic: 'GdkP' */
    24 + 339,                   /* header length + pixel_data length */
    0x2010002,                  /* pixdata_type */
    52,                         /* rowstride */
    13,                         /* width */
    13,                         /* height */
    /* pixel_data: */
    "\1\0\377\0\0\21333f\377\203\0\377\0\0\1"
    "3f\231\377\207\377\377\377\377" "\1" "3f\231\377\204\0\377\0\0\1"
    "3f\231\377\202\377\377\377\377\3\231"
    "\231\314\377\377\377\377\377\231\231\314\377\202\377\377\377\377\1"
    "3" "f\231\377\204\0\377\0\0\1"
    "3f\231\377\203\377\377\377\377\1\231\231\314"
    "\377\203\377\377\377\377\1"
    "3f\231\377\204\0\377\0\0\2023f\231\377\205"
    "\377\377\377\377\2023f\231\377\205\0\377\0\0\2023f\231\377\3\377\377"
    "\377\377\231\231\314\377\377\377\377\377\2023f\231\377\207\0\377\0\0"
    "\2023f\231\377\1\377\377\377\377\2023f\231\377\207\0\377\0\0\2023f\231"
    "\377\3\377\377\377\377\231\231\314\377\377\377\377\377\2023f\231\377"
    "\205\0\377\0\0\2023f\231\377\205\377\377\377\377\2023f\231\377\204\0"
    "\377\0\0\1"
    "3f\231\377\203\377\377\377\377\1\231\231\314\377\203\377"
    "\377\377\377\1" "3f\231\377\204\0\377\0\0\1"
    "3f\231\377\202\377\377\377"
    "\377\3\231\231\314\377\377\377\377\377\231\231\314\377\202\377\377\377"
    "\377\1" "3f\231\377\204\0\377\0\0\11"
    "3f\231\377\377\377\377\377\231\231"
    "\314\377\377\377\377\377\231\231\314\377\377\377\377\377\231\231\314"
    "\377\377\377\377\3773f\231\377\203\0\377\0\0\21333f\377\1\0\377\0\0",
};


/* GdkPixbuf RGBA C-Source image dump 1-byte-run-length-encoded */

static const GdkPixdata left_icon_pixdata = {
    0x47646b50,                 /* Pixbuf magic: 'GdkP' */
    24 + 144,                   /* header length + pixel_data length */
    0x2010002,                  /* pixdata_type */
    48,                         /* rowstride */
    12,                         /* width */
    13,                         /* height */
    /* pixel_data: */
    "\223\0\377\0\0\1\231\231\314\377\212\0\377\0\0\202\231\231\314\377\211"
    "\0\377\0\0\203\231\231\314\377\210\0\377\0\0\204\231\231\314\377\207"
    "\0\377\0\0\205\231\231\314\377\206\0\377\0\0\206\231\231\314\377\207"
    "\0\377\0\0\1" "3f\231\377\204\231\231\314\377\210\0\377\0\0\1"
    "3f\231" "\377\203\231\231\314\377\211\0\377\0\0\1"
    "3f\231\377\202\231\231\314"
    "\377\206\0\377\0\0\204\314\314\314\377\2"
    "3f\231\377\231\231\314\377" "\210\0\377\0\0\203\314\314\314\377\1"
    "3f\231\377\220\0\377\0\0",
};


/* GdkPixbuf RGBA C-Source image dump 1-byte-run-length-encoded */

static const GdkPixdata library_icon_pixdata = {
    0x47646b50,                 /* Pixbuf magic: 'GdkP' */
    24 + 272,                   /* header length + pixel_data length */
    0x2010002,                  /* pixdata_type */
    60,                         /* rowstride */
    15,                         /* width */
    13,                         /* height */
    /* pixel_data: */
    "\205\0\377\0\0\204\231\231\314\377\212\0\377\0\0\1\231\231\314\377\204"
    "\377\377\377\377\1\231\231\314\377\210\0\377\0\0\2\231\231\314\377\377"
    "\377\377\377\205\314\314\377\377\204\231\231\314\377\204\0\377\0\0\2"
    "\231\231\314\377\377\377\377\377\211\314\314\377\377\2"
    "3f\231\377\0" "\377\0\0\212\231\231\314\377\203\314\314\377\377\2"
    "3f\231\377\231\231" "\314\377\212\377\377\377\377\1"
    "3f\231\377\202\314\314\377\377\3" "3f"
    "\231\377\231\231\314\377\377\377\377\377\211\314\314\377\377\1"
    "3f\231" "\377\202\314\314\377\377\4"
    "3f\231\377\0\377\0\0\231\231\314\377\377"
    "\377\377\377\211\314\314\377\377\6"
    "3f\231\377\314\314\377\3773f\231"
    "\377\0\377\0\0\231\231\314\377\377\377\377\377\211\314\314\377\377\3"
    "3f\231\377\314\314\377\3773f\231\377\202\0\377\0\0\2\231\231\314\377"
    "\377\377\377\377\211\314\314\377\377\2023f\231\377\202\0\377\0\0\2\231"
    "\231\314\377\377\377\377\377\211\314\314\377\377\2023f\231\377\203\0"
    "\377\0\0\2133f\231\377\220\0\377\0\0",
};


/* GdkPixbuf RGBA C-Source image dump 1-byte-run-length-encoded */

static const GdkPixdata menu_icon_pixdata = {
    0x47646b50,                 /* Pixbuf magic: 'GdkP' */
    24 + 135,                   /* header length + pixel_data length */
    0x2010002,                  /* pixdata_type */
    52,                         /* rowstride */
    13,                         /* width */
    13,                         /* height */
    /* pixel_data: */
    "\23433f\377\211\377\377\377\377\20433f\377\1\377\377\377\377\2063f\231"
    "\0\202\377\377\377\377\20433f\377\211\377\377\377\377\20433f\377\203"
    "\377\377\377\377\2043f\231\0\202\377\377\377\377\20433f\377\211\377\377"
    "\377\377\20433f\377\203\377\377\377\377\2043f\231\0\202\377\377\377\377"
    "\20433f\377\211\377\377\377\377\20433f\377\203\377\377\377\377\2043f"
    "\231\0\202\377\377\377\377\20433f\377\211\377\377\377\377\23433f\377",
};


/* GdkPixbuf RGBA C-Source image dump 1-byte-run-length-encoded */

static const GdkPixdata right_icon_pixdata = {
    0x47646b50,                 /* Pixbuf magic: 'GdkP' */
    24 + 144,                   /* header length + pixel_data length */
    0x2010002,                  /* pixdata_type */
    52,                         /* rowstride */
    13,                         /* width */
    13,                         /* height */
    /* pixel_data: */
    "\222\0\377\0\0\1\231\231\314\377\214\0\377\0\0\202\231\231\314\377\213"
    "\0\377\0\0\203\231\231\314\377\212\0\377\0\0\204\231\231\314\377\211"
    "\0\377\0\0\205\231\231\314\377\210\0\377\0\0\206\231\231\314\377\207"
    "\0\377\0\0\204\231\231\314\377\1"
    "3f\231\377\210\0\377\0\0\203\231\231" "\314\377\1"
    "3f\231\377\211\0\377\0\0\202\231\231\314\377\1" "3f\231\377"
    "\212\0\377\0\0\2\231\231\314\3773f\231\377\204\314\314\314\377\207\0"
    "\377\0\0\1" "3f\231\377\203\314\314\314\377\221\0\377\0\0",
};


/* GdkPixbuf RGBA C-Source image dump 1-byte-run-length-encoded */

static const GdkPixdata viewer_icon_pixdata = {
    0x47646b50,                 /* Pixbuf magic: 'GdkP' */
    24 + 1138,                  /* header length + pixel_data length */
    0x2010002,                  /* pixdata_type */
    128,                        /* rowstride */
    32,                         /* width */
    32,                         /* height */
    /* pixel_data: */
    "\217\0\377\0\0\2\303\303\303\377ee\232\377\203ee0\377\3ee\232\377\232"
    "\232\232\377\303\303\303\377\225\0\377\0\0\202e\232\317\377\3"
    "0e\232"
    "\377ee0\377\232\232\232\377\202\317\232\317\377\202\317\232\232\377\3"
    "\212\212\212\377000\377\303\303\303\377\222\0\377\0\0\204e\232\317\377"
    "\202\212\212\212\377\1\317\232\317\377\206\317\232\232\377\1"
    "000\377"
    "\221\0\377\0\0\7e\232\317\3770e\232\377\232\232\232\377ee\232\377\212"
    "\212\212\377\317\232\232\377ee0\377\202\377\377\377\377\1\317\232\317"
    "\377\203\317\232\232\377\2\212\212\212\377000\377\220\0\377\0\0\202e"
    "\232\317\377\2" "000\377\232e\0\377\203\317\232\0\377\3"
    "00\0\377\317"
    "\232\317\377\377\377\377\377\203\317\232\317\377\3\212\212\212\377\0"
    "\0\0\377\303\303\303\377\217\0\377\0\0\202e\232\317\377\2\212\212\212"
    "\377\232\2320\377\204\317\232\0\377\3\2320\0\377\317\232\232\377\232"
    "e0\377\202ee0\377\4"
    "000\377EEE\3770e\232\377e\232\317\377\216\0\377"
    "\0\0\203e\232\317\377\2EEE\377\317\317\232\377\203\317\232\0\377\7"
    "0"
    "0\0\377\0\0\0\377\212\212\212\377\317\317\232\377\232e0\377\232e\0\377"
    "\232\232\232\377\204e\232\317\377\215\0\377\0\0\203e\232\317\377\2EE"
    "E\377\317\317\232\377\202\317\232\0\377\3\0\0\0\377\232e0\37700\0\377"
    "\202\317\232\232\377\1" "000\377\202\317\232\0\377\2"
    "00\0\3770e\232\377"
    "\202e\232\317\377\214\0\377\0\0\204e\232\317\377\2ee0\377\317\317\232"
    "\377\202\317\232\0\377\1"
    "00\0\377\204\317\232\232\377\2EEE\37700\0\377"
    "\202\317\232\0\377\2e0\0\3770e\232\377\202e\232\317\377\213\0\377\0\0"
    "\204e\232\317\377\6"
    "0e\232\377EEE\377\317\317\232\377\317\232\0\377"
    "\2320\0\377000\377\204\317\232\232\377\1e00\377\203\317\232\0\377\1e"
    "e0\377\202e\232\317\377\213\0\377\0\0\205e\232\317\377\5EEE\377\212\212"
    "\212\377\317\317\232\377\317\232\0\377\232e\0\377\20200\0\377\3\2320"
    "0\377e00\377e0\0\377\203\317\232\0\377\1"
    "000\377\202e\232\317\377\213"
    "\0\377\0\0\204e\232\317\377\5\212\212\212\377\317\317\232\377EEE\377"
    "\232e0\377\317\317\232\377\203\317\232\0\377\1\232e\0\377\205\317\232"
    "\0\377\1ee0\377\202e\232\317\377\213\0\377\0\0\204e\232\317\377\6\0\0"
    "\0\377\317\317\232\377\232\232\232\377\0\0\0\377EEE\377\317\317\232\377"
    "\207\317\232\0\377\2"
    "00\0\3770e\232\377\202e\232\317\377\213\0\377\0"
    "\0\204e\232\317\377\6\0\0\0\377\317\317\232\377EEE\377\232\232\232\377"
    "\212\212\212\377ee\232\377\206\317\317\232\377\2\2320\0\377000\377\203"
    "e\232\317\377\213\0\377\0\0\204e\232\317\377\12EEE\377\317\317\232\377"
    "00\0\377ee\232\377e\232\317\3770e\232\377\212\212\212\377EEE\377ee0\377"
    "\212\212\212\377\203EEE\377\204e\232\317\377\214\0\377\0\0\203e\232\317"
    "\377\5ee0\377\317\317\232\377\232\2320\377\0\0\0\377\232\232\232\377"
    "\203e\232\317\377\4\212\212\212\377\317\317\232\377\0\0\0\3770e\232\377"
    "\204e\232\317\377\215\0\377\0\0\203e\232\317\377\5"
    "0e\232\377\212\212"
    "\212\377\317\317\232\377EEE\377000\377\203e\232\317\377\4\0\0\0\377\317"
    "\317\232\377EEE\377\212\212\212\377\204e\232\317\377\216\0\377\0\0\203"
    "e\232\317\377\202\212\212\212\377\1\317\317\232\377\202EEE\377\202\232"
    "\232\232\377\4ee0\377\317\317\232\377\232\2320\377ee\232\377\203e\232"
    "\317\377\220\0\377\0\0\203e\232\317\377\2"
    "0e\232\377\232\2320\377\202"
    "\317\317\232\377\2\232\2320\377\232\232\232\377\202\317\317\232\377\2"
    "EEE\3770e\232\377\202e\232\317\377\222\0\377\0\0\203e\232\317\377\2\212"
    "\212\212\377\232\2320\377\204\317\317\232\377\2\232\2320\377ee\232\377"
    "\202e\232\317\377\224\0\377\0\0\203e\232\317\377\6"
    "0e\232\377ee\232"
    "\377\232\232\232\3770e\232\377\232\232\232\3770e\232\377\202e\232\317"
    "\377\227\0\377\0\0\207e\232\317\377\377\0\377\0\0\377\0\377\0\0\317\0"
    "\377\0\0",
};


/* GdkPixbuf RGBA C-Source image dump 1-byte-run-length-encoded */

static const GdkPixdata wait_icon_pixdata = {
    0x47646b50,                 /* Pixbuf magic: 'GdkP' */
    24 + 339,                   /* header length + pixel_data length */
    0x2010002,                  /* pixdata_type */
    52,                         /* rowstride */
    13,                         /* width */
    13,                         /* height */
    /* pixel_data: */
    "\1\0\377\0\0\21333f\377\203\0\377\0\0\1"
    "3f\231\377\207\377\377\377\377" "\1" "3f\231\377\204\0\377\0\0\1"
    "3f\231\377\202\377\377\377\377\3\231"
    "\231\314\377\377\377\377\377\231\231\314\377\202\377\377\377\377\1"
    "3" "f\231\377\204\0\377\0\0\1"
    "3f\231\377\203\377\377\377\377\1\231\231\314"
    "\377\203\377\377\377\377\1"
    "3f\231\377\204\0\377\0\0\2023f\231\377\205"
    "\377\377\377\377\2023f\231\377\205\0\377\0\0\2023f\231\377\3\377\377"
    "\377\377\231\231\314\377\377\377\377\377\2023f\231\377\207\0\377\0\0"
    "\2023f\231\377\1\377\377\377\377\2023f\231\377\207\0\377\0\0\2023f\231"
    "\377\3\377\377\377\377\231\231\314\377\377\377\377\377\2023f\231\377"
    "\205\0\377\0\0\2023f\231\377\205\377\377\377\377\2023f\231\377\204\0"
    "\377\0\0\1"
    "3f\231\377\203\377\377\377\377\1\231\231\314\377\203\377"
    "\377\377\377\1" "3f\231\377\204\0\377\0\0\1"
    "3f\231\377\202\377\377\377"
    "\377\3\231\231\314\377\377\377\377\377\231\231\314\377\202\377\377\377"
    "\377\1" "3f\231\377\204\0\377\0\0\11"
    "3f\231\377\377\377\377\377\231\231"
    "\314\377\377\377\377\377\231\231\314\377\377\377\377\377\231\231\314"
    "\377\377\377\377\3773f\231\377\203\0\377\0\0\21333f\377\1\0\377\0\0",
};




void InitializeIcons ()
{
    GtkIconFactory*  factory;
    GtkIconSet*      iconset;

    /* create our icon factory */
    factory = gtk_icon_factory_new ();

    iconset =
        gtk_icon_set_new_from_pixbuf (gdk_pixbuf_from_pixdata
                                      (&left_icon_pixdata, TRUE, NULL));
    gtk_icon_factory_add (factory, "plucker-left-icon", iconset);

    iconset =
        gtk_icon_set_new_from_pixbuf (gdk_pixbuf_from_pixdata
                                      (&home_icon_pixdata, TRUE, NULL));
    gtk_icon_factory_add (factory, "plucker-home-icon", iconset);

    iconset =
        gtk_icon_set_new_from_pixbuf (gdk_pixbuf_from_pixdata
                                      (&right_icon_pixdata, TRUE, NULL));
    gtk_icon_factory_add (factory, "plucker-right-icon", iconset);

    iconset =
        gtk_icon_set_new_from_pixbuf (gdk_pixbuf_from_pixdata
                                      (&library_icon_pixdata, TRUE, NULL));
    gtk_icon_factory_add (factory, "plucker-library-icon", iconset);

    /* add the factory to the default list of icon factories */
    gtk_icon_factory_add_default (factory);
}

typedef struct {
    gpointer    user_data;
    gboolean    pressed;
    void        (*callback) (gpointer);
    GtkWidget*  event_box;
    GtkFrame*   frame;
} ImageButtonCallbackData;

static gboolean ImageButtonCallback
    (
    GtkWidget*       event_box,
    GdkEventButton*  event,
    gpointer         user_data
    )
{
    ImageButtonCallbackData *cbdata =
        (ImageButtonCallbackData *) user_data;

/*
   fprintf (stderr, "State is %d, type is %d, button is %d, x is %f, y is %f, callback is %p\n",
   event->state, event->type, event->button, event->x, event->y, cbdata);
   fprintf (stderr, "widget.width is %d, widget.height is %d\n",
   event_box->allocation.width, event_box->allocation.height);
   fprintf (stderr, "Pressed is %s; callback is %p, userdata is %p\n",
   cbdata->pressed ? "TRUE" : "FALSE", cbdata->callback, cbdata->user_data);
 */

    if (!cbdata->pressed && event->type == GDK_BUTTON_PRESS) {
        cbdata->pressed = TRUE;
        gtk_frame_set_shadow_type (cbdata->frame, GTK_SHADOW_IN);
    }
    else if (cbdata->pressed && event->type == GDK_BUTTON_RELEASE) {
        cbdata->pressed = FALSE;
        gtk_frame_set_shadow_type (cbdata->frame, GTK_SHADOW_OUT);
        if (event->x < event_box->allocation.width
            && event->y < event_box->allocation.height)
            (*cbdata->callback) (cbdata->user_data);
    }

    return TRUE;
}

GtkWidget* CreateImageButton
    (
    char*    stock_id,
    void     (*cb) (gpointer),
    gpointer  user_data
    )
{
    ImageButtonCallbackData*  cbdata;
    GtkWidget*                image;
    GtkWidget*                event_box;
    GtkWidget*                frame;

    image = gtk_image_new_from_stock (stock_id, GTK_ICON_SIZE_SMALL_TOOLBAR);
    event_box = gtk_event_box_new ();
    gtk_container_set_border_width (GTK_CONTAINER (event_box), 3);
    gtk_container_add (GTK_CONTAINER (event_box), image);
    frame = gtk_frame_new (NULL);
    gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_OUT);
    gtk_container_add (GTK_CONTAINER (frame), event_box);

    cbdata = (ImageButtonCallbackData *)
              malloc (sizeof (ImageButtonCallbackData));
    cbdata->user_data = user_data;
    cbdata->callback = cb;
    cbdata->pressed = FALSE;
    cbdata->event_box = GTK_WIDGET (event_box);
    cbdata->frame = GTK_FRAME (frame);

    g_signal_connect (G_OBJECT (event_box), "button_release_event",
                      G_CALLBACK (ImageButtonCallback), cbdata);
    g_signal_connect (G_OBJECT (event_box), "button_press_event",
                      G_CALLBACK (ImageButtonCallback), cbdata);

    return frame;
}


#define READ_BIGENDIAN_SHORT(p) (((p)[0] << 8)|((p)[1]))
#define READ_BIGENDIAN_LONG(p)  (((p)[0] << 24)|((p)[1] << 16)|((p)[2] << 8)|((p)[3]))

#define PALM_IS_COMPRESSED_FLAG       0x8000
#define PALM_HAS_COLORMAP_FLAG        0x4000
#define PALM_HAS_TRANSPARENCY_FLAG    0x2000
#define PALM_DIRECT_COLOR_FLAG        0x0400
#define PALM_4_BYTE_FIELD_FLAG        0x0200

#define PALM_COMPRESSION_SCANLINE     0x00
#define PALM_COMPRESSION_RLE          0x01
#define PALM_COMPRESSION_PACKBITS     0x02
#define PALM_COMPRESSION_NONE         0xFF

#define PALM_COLORMAP_SIZE            232

typedef struct {
    unsigned char red;
    unsigned char green;
    unsigned char blue;
} ColorMapEntry;

static ColorMapEntry Palm8BitColormap[] = {
    {255, 255, 255},
    {255, 204, 255},
    {255, 153, 255},
    {255, 102, 255},
    {255, 51, 255},
    {255, 0, 255},
    {255, 255, 204},
    {255, 204, 204},
    {255, 153, 204},
    {255, 102, 204},
    {255, 51, 204},
    {255, 0, 204},
    {255, 255, 153},
    {255, 204, 153},
    {255, 153, 153},
    {255, 102, 153},
    {255, 51, 153},
    {255, 0, 153},
    {204, 255, 255},
    {204, 204, 255},
    {204, 153, 255},
    {204, 102, 255},
    {204, 51, 255},
    {204, 0, 255},
    {204, 255, 204},
    {204, 204, 204},
    {204, 153, 204},
    {204, 102, 204},
    {204, 51, 204},
    {204, 0, 204},
    {204, 255, 153},
    {204, 204, 153},
    {204, 153, 153},
    {204, 102, 153},
    {204, 51, 153},
    {204, 0, 153},
    {153, 255, 255},
    {153, 204, 255},
    {153, 153, 255},
    {153, 102, 255},
    {153, 51, 255},
    {153, 0, 255},
    {153, 255, 204},
    {153, 204, 204},
    {153, 153, 204},
    {153, 102, 204},
    {153, 51, 204},
    {153, 0, 204},
    {153, 255, 153},
    {153, 204, 153},
    {153, 153, 153},
    {153, 102, 153},
    {153, 51, 153},
    {153, 0, 153},
    {102, 255, 255},
    {102, 204, 255},
    {102, 153, 255},
    {102, 102, 255},
    {102, 51, 255},
    {102, 0, 255},
    {102, 255, 204},
    {102, 204, 204},
    {102, 153, 204},
    {102, 102, 204},
    {102, 51, 204},
    {102, 0, 204},
    {102, 255, 153},
    {102, 204, 153},
    {102, 153, 153},
    {102, 102, 153},
    {102, 51, 153},
    {102, 0, 153},
    {51, 255, 255},
    {51, 204, 255},
    {51, 153, 255},
    {51, 102, 255},
    {51, 51, 255},
    {51, 0, 255},
    {51, 255, 204},
    {51, 204, 204},
    {51, 153, 204},
    {51, 102, 204},
    {51, 51, 204},
    {51, 0, 204},
    {51, 255, 153},
    {51, 204, 153},
    {51, 153, 153},
    {51, 102, 153},
    {51, 51, 153},
    {51, 0, 153},
    {0, 255, 255},
    {0, 204, 255},
    {0, 153, 255},
    {0, 102, 255},
    {0, 51, 255},
    {0, 0, 255},
    {0, 255, 204},
    {0, 204, 204},
    {0, 153, 204},
    {0, 102, 204},
    {0, 51, 204},
    {0, 0, 204},
    {0, 255, 153},
    {0, 204, 153},
    {0, 153, 153},
    {0, 102, 153},
    {0, 51, 153},
    {0, 0, 153},
    {255, 255, 102},
    {255, 204, 102},
    {255, 153, 102},
    {255, 102, 102},
    {255, 51, 102},
    {255, 0, 102},
    {255, 255, 51},
    {255, 204, 51},
    {255, 153, 51},
    {255, 102, 51},
    {255, 51, 51},
    {255, 0, 51},
    {255, 255, 0},
    {255, 204, 0},
    {255, 153, 0},
    {255, 102, 0},
    {255, 51, 0},
    {255, 0, 0},
    {204, 255, 102},
    {204, 204, 102},
    {204, 153, 102},
    {204, 102, 102},
    {204, 51, 102},
    {204, 0, 102},
    {204, 255, 51},
    {204, 204, 51},
    {204, 153, 51},
    {204, 102, 51},
    {204, 51, 51},
    {204, 0, 51},
    {204, 255, 0},
    {204, 204, 0},
    {204, 153, 0},
    {204, 102, 0},
    {204, 51, 0},
    {204, 0, 0},
    {153, 255, 102},
    {153, 204, 102},
    {153, 153, 102},
    {153, 102, 102},
    {153, 51, 102},
    {153, 0, 102},
    {153, 255, 51},
    {153, 204, 51},
    {153, 153, 51},
    {153, 102, 51},
    {153, 51, 51},
    {153, 0, 51},
    {153, 255, 0},
    {153, 204, 0},
    {153, 153, 0},
    {153, 102, 0},
    {153, 51, 0},
    {153, 0, 0},
    {102, 255, 102},
    {102, 204, 102},
    {102, 153, 102},
    {102, 102, 102},
    {102, 51, 102},
    {102, 0, 102},
    {102, 255, 51},
    {102, 204, 51},
    {102, 153, 51},
    {102, 102, 51},
    {102, 51, 51},
    {102, 0, 51},
    {102, 255, 0},
    {102, 204, 0},
    {102, 153, 0},
    {102, 102, 0},
    {102, 51, 0},
    {102, 0, 0},
    {51, 255, 102},
    {51, 204, 102},
    {51, 153, 102},
    {51, 102, 102},
    {51, 51, 102},
    {51, 0, 102},
    {51, 255, 51},
    {51, 204, 51},
    {51, 153, 51},
    {51, 102, 51},
    {51, 51, 51},
    {51, 0, 51},
    {51, 255, 0},
    {51, 204, 0},
    {51, 153, 0},
    {51, 102, 0},
    {51, 51, 0},
    {51, 0, 0},
    {0, 255, 102},
    {0, 204, 102},
    {0, 153, 102},
    {0, 102, 102},
    {0, 51, 102},
    {0, 0, 102},
    {0, 255, 51},
    {0, 204, 51},
    {0, 153, 51},
    {0, 102, 51},
    {0, 51, 51},
    {0, 0, 51},
    {0, 255, 0},
    {0, 204, 0},
    {0, 153, 0},
    {0, 102, 0},
    {0, 51, 0},
    {17, 17, 17},
    {34, 34, 34},
    {68, 68, 68},
    {85, 85, 85},
    {119, 119, 119},
    {136, 136, 136},
    {170, 170, 170},
    {187, 187, 187},
    {221, 221, 221},
    {238, 238, 238},
    {192, 192, 192},
    {128, 0, 0},
    {128, 0, 128},
    {0, 128, 0},
    {0, 128, 128},
    {0, 0, 0},
    {0, 0, 0},
    {0, 0, 0},
    {0, 0, 0},
    {0, 0, 0},
    {0, 0, 0},
    {0, 0, 0},
    {0, 0, 0},
    {0, 0, 0},
    {0, 0, 0},
    {0, 0, 0},
    {0, 0, 0},
    {0, 0, 0},
    {0, 0, 0},
    {0, 0, 0},
    {0, 0, 0},
    {0, 0, 0},
    {0, 0, 0},
    {0, 0, 0},
    {0, 0, 0},
    {0, 0, 0},
    {0, 0, 0},
    {0, 0, 0},
    {0, 0, 0},
    {0, 0, 0},
    {0, 0, 0}
};

static ColorMapEntry Palm1BitColormap[] = {
    {255, 255, 255},
    {0, 0, 0}
};

static ColorMapEntry Palm2BitColormap[] = {
    {255, 255, 255},
    {192, 192, 192},
    {128, 128, 128},
    {0, 0, 0}
};

static ColorMapEntry Palm4BitColormap[] = {
    {255, 255, 255},
    {238, 238, 238},
    {221, 221, 221},
    {204, 204, 204},
    {187, 187, 187},
    {170, 170, 170},
    {153, 153, 153},
    {136, 136, 136},
    {119, 119, 119},
    {102, 102, 102},
    {85, 85, 85},
    {68, 68, 68},
    {51, 51, 51},
    {34, 34, 34},
    {17, 17, 17},
    {0, 0, 0}
};

static GdkPixbuf* TranscribePalmImageToGdkPixbuf
    (
    unsigned char*  image_bytes_in,
    int             byte_count_in,
    double          scale
    )
{
    ColorMapEntry*  colormap;
    unsigned char*  palm_ptr;
    unsigned char*  inbyte;
    unsigned char*  rowbuf;
    unsigned char*  lastrow;
    unsigned char*  imagedatastart;
    unsigned char*  palmimage;
    unsigned int    width;
    unsigned int    height;
    unsigned int    bytes_per_row;
    unsigned int    flags;
    unsigned int    next_depth_offset;
    unsigned int    bits_per_pixel;
    unsigned int    version;
    unsigned int    transparent_index;
    unsigned int    compression_type;
    unsigned int    i;
    unsigned int    j;
    unsigned int    inval;
    unsigned int    inbit;
    unsigned int    mask;
    unsigned int    incount;
    unsigned int    palm_red_bits;
    unsigned int    palm_green_bits;
    unsigned int    palm_blue_bits;
    GdkPixbuf*      pixbuf;
    GdkPixbuf*      scaled_pixbuf;
    guchar*         pixels;
    int             row_stride;
    int             scaled_width;
    int             scaled_height;

    palmimage = image_bytes_in;
    width = READ_BIGENDIAN_SHORT (palmimage + 0);
    height = READ_BIGENDIAN_SHORT (palmimage + 2);
    bytes_per_row = READ_BIGENDIAN_SHORT (palmimage + 4);
    flags = READ_BIGENDIAN_SHORT (palmimage + 6);
    bits_per_pixel = palmimage[8];
    version = palmimage[9];
    next_depth_offset = READ_BIGENDIAN_SHORT (palmimage + 10);
    transparent_index = palmimage[12];
    compression_type = palmimage[13];
    /* bytes 14 and 15 are reserved by Palm and always 0 */

#if 0
    g_warning
        ("Palm image is %dx%d, %d bpp, version %d, flags 0x%x, compression %d",
         width, height, bits_per_pixel, version, flags, compression_type);
#endif

    if (compression_type == PALM_COMPRESSION_PACKBITS) {
        g_warning ("Image uses packbits compression; not yet supported");
        return FALSE;
    }
    else if ((compression_type != PALM_COMPRESSION_NONE) &&
             (compression_type != PALM_COMPRESSION_RLE) &&
             (compression_type != PALM_COMPRESSION_SCANLINE)) {
        g_warning ("Image uses unknown compression, code 0x%x",
                   compression_type);
        return FALSE;
    }

    /* as of PalmOS 4.0, there are 6 different kinds of Palm pixmaps:

       1, 2, or 4 bit grayscale
       8-bit StaticColor using the Palm standard colormap
       8-bit PseudoColor using a user-specified colormap
       16-bit DirectColor using 5 bits for red, 6 for green, and 5 for blue

       Each of these can be compressed with one of four compression schemes,
       "RLE", "Scanline", "PackBits", or none.

       We begin by constructing the colormap.
     */

    if (flags & PALM_HAS_COLORMAP_FLAG) {
        g_warning
            ("Palm images with custom colormaps are not currently supported.\n");
        return FALSE;
    }
    else if (bits_per_pixel == 1) {
        colormap = Palm1BitColormap;
        imagedatastart = palmimage + 16;
    }
    else if (bits_per_pixel == 2) {
        colormap = Palm2BitColormap;
        imagedatastart = palmimage + 16;
    }
    else if (bits_per_pixel == 4) {
        colormap = Palm4BitColormap;
        imagedatastart = palmimage + 16;
    }
    else if (bits_per_pixel == 8) {
        colormap = Palm8BitColormap;
        imagedatastart = palmimage + 16;
    }
    else if (bits_per_pixel == 16 && (flags & PALM_DIRECT_COLOR_FLAG)) {
        colormap = NULL;
        palm_red_bits = palmimage[16];
        palm_green_bits = palmimage[17];
        palm_blue_bits = palmimage[18];
        if (palm_blue_bits > 8 || palm_green_bits > 8 || palm_red_bits > 8) {
            g_warning
                ("Can't handle this format DirectColor image -- too wide in some color (%d:%d:%d)\n",
                 palm_red_bits, palm_green_bits, palm_blue_bits);
            return FALSE;
        }
        if (bits_per_pixel > (8 * sizeof (unsigned long))) {
            g_warning
                ("Can't handle this format DirectColor image -- too many bits per pixel (%d)\n",
                 bits_per_pixel);
            return FALSE;
        }
        imagedatastart = palmimage + 24;
    }
    else {
        g_warning ("Unknown bits-per-pixel of %d encountered.\n",
                   bits_per_pixel);
        return FALSE;
    }

    /* now create the GDK pixbuf */
    pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE, 8, width, height);
    pixels = gdk_pixbuf_get_pixels (pixbuf);
    row_stride = gdk_pixbuf_get_rowstride (pixbuf);

    /* row by row, uncompress the Palm image and copy it to the pixbuf buffer */
    rowbuf = (unsigned char *) malloc (bytes_per_row * width);
    lastrow = (unsigned char *) malloc (bytes_per_row * width);

    for (i = 0, palm_ptr = imagedatastart; i < height; ++i) {

        /* first, uncompress the Palm image */
        if ((flags & PALM_IS_COMPRESSED_FLAG)
            && (compression_type == PALM_COMPRESSION_RLE)) {
            for (j = 0; j < bytes_per_row;) {
                incount = *palm_ptr++;
                inval = *palm_ptr++;
                memset (rowbuf + j, inval, incount);
                j += incount;
            }
        }
        else if ((flags & PALM_IS_COMPRESSED_FLAG)
                 && (compression_type == PALM_COMPRESSION_SCANLINE)) {
            for (j = 0; j < bytes_per_row; j += 8) {
                incount = *palm_ptr++;
                inval =
                    ((bytes_per_row - j) < 8) ? (bytes_per_row - j) : 8;
                for (inbit = 0; inbit < inval; inbit += 1) {
                    if (incount & (1 << (7 - inbit)))
                        rowbuf[j + inbit] = *palm_ptr++;
                    else
                        rowbuf[j + inbit] = lastrow[j + inbit];
                }
            }
            memcpy (lastrow, rowbuf, bytes_per_row);
        }
        else if (((flags & PALM_IS_COMPRESSED_FLAG) &&
                  (compression_type == PALM_COMPRESSION_NONE)) ||
                 (flags && PALM_IS_COMPRESSED_FLAG) == 0) {
            memcpy (rowbuf, palm_ptr, bytes_per_row);
            palm_ptr += bytes_per_row;
        }

        /* next, write it to the GDK pixbuf */
        if (colormap) {
            mask = (1 << bits_per_pixel) - 1;
            for (inbit = 8 - bits_per_pixel, inbyte = rowbuf, j = 0;
                 j < width; ++j) {
                inval = ((*inbyte) & (mask << inbit)) >> inbit;
                /* correct for oddity of the 8-bit color Palm pixmap... */
                if ((bits_per_pixel == 8) && (inval == 0xFF))
                    inval = 231;
                /* now lookup the correct color and set the pixel in the GTK bitmap */
                pixels[(j * 3) + 0] = colormap[inval].red;
                pixels[(j * 3) + 1] = colormap[inval].green;
                pixels[(j * 3) + 2] = colormap[inval].blue;
                if (!inbit) {
                    ++inbyte;
                    inbit = 8 - bits_per_pixel;
                }
                else {
                    inbit -= bits_per_pixel;
                }
            }
        }
        else if (!colormap && bits_per_pixel == 16) {
            for (inbyte = rowbuf, j = 0; j < width; ++j) {
                inval = (inbyte[0] << 8) | inbyte[1];
#if 0
                g_warning ("pixel is %d,%d (%02x:%02x:%02x)",
                           j, i,
                           (inval >> (bits_per_pixel - palm_red_bits)) &
                           ((1 << palm_red_bits) - 1),
                           (inval >> palm_blue_bits) &
                           ((1 << palm_green_bits) - 1),
                           (inval >> 0) & ((1 << palm_blue_bits) - 1));
#endif
                pixels[(j * 3) + 0] =
                    (inval >> (bits_per_pixel - palm_red_bits)) &
                    ((1 << palm_red_bits) - 1);
                pixels[(j * 3) + 1] =
                    (inval >> palm_blue_bits) & ((1 << palm_green_bits) -
                                                 1);
                pixels[(j * 3) + 2] =
                    (inval >> 0) & ((1 << palm_blue_bits) - 1);
                inbyte += 2;
            }
        }

        pixels += row_stride;
    }

    free (rowbuf);
    free (lastrow);

    scaled_width = MAX ((int) (scale * width), 1);
    scaled_height = MAX ((int) (scale * height), 1);
    if (scaled_width > 0 && scaled_height > 0
        && (scaled_width != width || scaled_height != height)) {
        scaled_pixbuf =
            gdk_pixbuf_scale_simple (pixbuf, scaled_width, scaled_height,
                                     GDK_INTERP_BILINEAR);
        g_object_unref (pixbuf);
        pixbuf = scaled_pixbuf;
    }

    return pixbuf;
}

typedef struct {
    plkr_Document*  doc;
    int             record_id;
    void*           data;
} CachedImage;

static gint CompareImageRecords
    (
    gconstpointer a,
    gconstpointer b
    )
{
    CachedImage*  ir1;
    CachedImage*  ir2;

    ir1 = (CachedImage *) a;
    ir2 = (CachedImage *) b;

    if (ir1->doc < ir2->doc)
        return -1;
    else if (ir1->doc > ir2->doc)
        return 1;
    else if (ir1->record_id < ir2->record_id)
        return -1;
    else if (ir1->record_id > ir2->record_id)
        return 1;
    else
        return 0;
}

#define PART(x,y) parts[x+y*cols]
typedef struct {
    GdkPixbuf* pixbuf;
    int height;
    int width;
} PARTS;
GdkPixbuf* GetImageRecord
    (
    plkr_Document*  doc,
    int             id,
    double          scale
    )
{
    plkr_DataRecordType  type;
    CachedImage*         image_record = NULL;
    CachedImage          temp;
    GdkPixbuf*           pixbuf = NULL;
    guchar*              data;
    int                  data_len;

    static GTree*  converted = NULL;

    if (converted == NULL) {
        converted = g_tree_new (CompareImageRecords);
    }
    else {
        temp.doc = doc;
        temp.record_id = id;
        image_record = (CachedImage *) g_tree_lookup (converted, &temp);
    }

    if (!image_record) {
        if ((data =
             plkr_GetRecordBytes (doc, id, &data_len, &type)) == NULL) {
            g_warning ("Can't read image record %d", id);
        }
        else if (type == PLKR_DRTYPE_IMAGE_COMPRESSED
                 || type == PLKR_DRTYPE_IMAGE) {
            pixbuf =
                TranscribePalmImageToGdkPixbuf (data + 8, data_len - 8,
                                                scale);
            if (pixbuf && converted) {
                image_record = malloc (sizeof (*image_record));
                image_record->doc = doc;
                image_record->record_id = id;
                image_record->data = (void *) pixbuf;
                g_tree_insert (converted, image_record, image_record);
            }
            else
                g_warning
                    ("NULL pixbuf returned from TranscribePalmImageToGdkPixbuf");
        }
        else if (type == PLKR_DRTYPE_MULTIIMAGE) {
            plkr_DataRecordType type;
            unsigned char record_bytes[0x10000];
            int record_bytes_len;
            int rows, cols;
            int x, y;
            int image_id;
            int high;
            int wide;
            int deep;
            PARTS* parts;
            GdkPixbuf* big_pixbuf;

            record_bytes_len = plkr_CopyRecordBytes (doc, id, &record_bytes[0],
                                                     sizeof (record_bytes),
                                                     &type);

            cols = READ_BIGENDIAN_SHORT (&record_bytes[8]);
            rows = READ_BIGENDIAN_SHORT (&record_bytes[10]);
            parts = (PARTS*) malloc (rows * cols * sizeof (PARTS));

            high = 0;
            for (y = 0; y < rows; y++) {
                wide = 0;
                for (x = 0; x < cols; x++) {
                    int offset = (6 + x + y * cols) * 2;

                    image_id = READ_BIGENDIAN_SHORT (&record_bytes[offset]);

                    PART(x, y).pixbuf = GetImageRecord (doc, image_id, scale);
                    PART(x, y).height = gdk_pixbuf_get_height
                                                        (PART(x, y).pixbuf);
                    PART(x, y).width = gdk_pixbuf_get_width (PART(x, y).pixbuf);
                    wide += PART(x, y).width;
                }
                high += PART(0, y).height;
                deep = gdk_pixbuf_get_bits_per_sample (PART(0, y).pixbuf);
            }

            big_pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE,
                                         deep, wide, high);
            high = 0;
            for (y = 0; y < rows; y++) {
                wide = 0;
                for (x = 0; x < cols; x++) {
                    gdk_pixbuf_copy_area (PART(x, y).pixbuf, 0, 0,
                                          PART(x, y).width, PART(x, y).height,
                                          big_pixbuf, wide, high);
                    wide += PART(x, y).width;
                }
                high += PART(0, y).height;
            }

            image_record = malloc (sizeof (*image_record));
            image_record->doc = doc;
            image_record->record_id = id;
            image_record->data = (void *) big_pixbuf;
            g_tree_insert (converted, image_record, image_record);
        }
        else {
            g_warning ("bad type %d on supposed image record %d", type,
                       id);
        }
    }
    return (image_record ? (GdkPixbuf *) (image_record->data) : NULL);
}

typedef struct {
    int width;
    int height;
} WidthHeight;

typedef struct GlyphRecord {
    int           dpi;
    int           nglyphs;
    WidthHeight*  sizes;
    GdkPixbuf**   glyphs;
    GdkPixbuf*    image;
    GdkPixbuf*    scaled_image;
    int           scaled_dpi;
} GlyphRecord;

static GlyphRecord* GetGlyphRecord
    (
    plkr_Document*  doc,
    int             id,
    double          scale
    )
{
    guchar*              data;
    int                  data_len;
    unsigned int         dpi;
    unsigned int         nglyphs;
    unsigned int         i;
    unsigned int         val;
    WidthHeight*         sizes;
    plkr_DataRecordType  type;
    GdkPixbuf*           pixbuf = NULL;
    GdkPixbuf**          glyphs;
    CachedImage*         image_record = NULL;
    CachedImage          temp;
    GlyphRecord*         glyph_record;

    static GTree*        converted = NULL;

    if (converted == NULL) {
        converted = g_tree_new (CompareImageRecords);
    }
    else {
        temp.doc = doc;
        temp.record_id = id;
        image_record = (CachedImage *) g_tree_lookup (converted, &temp);
    }

    if (!image_record) {
        if ((data =
             plkr_GetRecordBytes (doc, id, &data_len, &type)) == NULL) {
            g_warning ("Can't read glyph record %d", id);
        }
        else if (type == PLKR_DRTYPE_GLYPHPAGE) {
            nglyphs = READ_BIGENDIAN_SHORT (data + 2);
            dpi = READ_BIGENDIAN_SHORT (data + 8);
            sizes =
                (WidthHeight *) malloc (sizeof (WidthHeight) * nglyphs);
            glyphs =
                (GdkPixbuf **) malloc (sizeof (GdkPixbuf *) * nglyphs);
            for (i = 0, data = data + 10; i < nglyphs; i++, data += 2) {
                val = READ_BIGENDIAN_SHORT (data);
                sizes[i].height = (val >> 9);
                sizes[i].width = (val & 0x1FF);
                glyphs[i] = NULL;
                /* fprintf (stderr, "sizes[i] = %d x %d\n", sizes[i].width, sizes[i].height); */
            }
            pixbuf =
                TranscribePalmImageToGdkPixbuf (data,
                                                data_len - (8 + 2 +
                                                            nglyphs * 2),
                                                scale);
            if (pixbuf && converted) {
                glyph_record = malloc (sizeof (*glyph_record));
                glyph_record->dpi = dpi;
                glyph_record->nglyphs = nglyphs;
                glyph_record->sizes = sizes;
                glyph_record->glyphs = glyphs;
                glyph_record->image = pixbuf;
                glyph_record->scaled_image = NULL;
                glyph_record->scaled_dpi = 0;
                image_record = malloc (sizeof (*image_record));
                image_record->doc = doc;
                image_record->record_id = id;
                image_record->data = glyph_record;
                g_tree_insert (converted, image_record, image_record);
            }
            else
                g_warning
                    ("NULL pixbuf returned from TranscribePalmImageToGdkPixbuf");
        }
        else {
            g_warning ("bad type %d on supposed glyph record %d", type,
                       id);
        }
    }
    return (image_record ? (GlyphRecord *) (image_record->data) : NULL);
}

GdkPixbuf* GetGlyph
    (
    plkr_Document*  doc,
    int             record_id,
    int             glyph_index,
    int             desired_dpi
    )
{
    GlyphRecord*  glyph_record;
    int           i;
    int           voffset;
    int           scaled_width;
    int           scaled_height;
    double scale_factor;

    glyph_record = GetGlyphRecord (doc, record_id, 1.0);
    if (!glyph_record)
        return NULL;
    if (glyph_index >= glyph_record->nglyphs)
        return NULL;

    /* OK, we have the glyph -- figure out where it is */
    for (i = 0, voffset = 2; i < glyph_index; i++) {
        voffset += (glyph_record->sizes[i].height + 4);
    }

    /* figure the scaling factor */
    scale_factor = (double) desired_dpi / (double) glyph_record->dpi;

    /* Scale the glyph page if necessary */
    if (!glyph_record->scaled_image
        || (desired_dpi != glyph_record->scaled_dpi)) {
        for (i = 0; i < glyph_record->nglyphs; i++)
            if (glyph_record->glyphs[i] != NULL)
                gdk_pixbuf_unref (glyph_record->glyphs[i]);
        if (glyph_record->scaled_image
            && (glyph_record->scaled_image != glyph_record->image))
            gdk_pixbuf_unref (glyph_record->scaled_image);
        if (glyph_record->dpi == desired_dpi) {
            glyph_record->scaled_image = glyph_record->image;
        }
        else {
            scaled_width =
                (int) (gdk_pixbuf_get_width (glyph_record->image) *
                       scale_factor);
            scaled_height =
                (int) (gdk_pixbuf_get_height (glyph_record->image) *
                       scale_factor);
            glyph_record->scaled_image =
                gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE, 8, scaled_width,
                                scaled_height);
            gdk_pixbuf_scale (glyph_record->image,
                              glyph_record->scaled_image, 0, 0,
                              scaled_width, scaled_height, 0, 0,
                              scale_factor, scale_factor,
                              GDK_INTERP_BILINEAR);
        }
        glyph_record->scaled_dpi = desired_dpi;
    }

    /* Already cut out? */
    if (!glyph_record->glyphs[glyph_index]) {
        /* cut out the glyph */
        glyph_record->glyphs[glyph_index] = gdk_pixbuf_new_subpixbuf
            (glyph_record->scaled_image, 0, (int) (voffset * scale_factor),
             MAX (1,
                  (int) (glyph_record->sizes[glyph_index].width *
                         scale_factor)), MAX (1,
                                              (int) (glyph_record->
                                                     sizes[glyph_index].
                                                     height *
                                                     scale_factor)));
    }

    return glyph_record->glyphs[glyph_index];
}

static gint ComparePointerInts
    (
    gconstpointer  p1,
    gconstpointer  p2
    )
{
    if (GPOINTER_TO_UINT (p1) < GPOINTER_TO_UINT (p2))
        return -1;
    else if (GPOINTER_TO_UINT (p1) > GPOINTER_TO_UINT (p2))
        return 1;
    else
        return 0;
}

GdkPixbuf* GetSpacerPixbuf
    (
    int  width_in_pixels
    )
{
    static GTree*      SpacerTree = NULL;
    static GdkPixbuf*  base_image;
    GdkPixbuf*         image;

    if (width_in_pixels > 1024) {
        g_warning ("Overly large (%d pixels) spacer image requested",
                   width_in_pixels);
        return NULL;
    }
    else if (width_in_pixels < 1) {
        g_warning ("Overly small (%d pixels) spacer image requested",
                   width_in_pixels);
        return NULL;
    }

    if (SpacerTree == NULL) {
        SpacerTree = g_tree_new (ComparePointerInts);
        base_image =
            gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE, 8, 1024, 1);
        gdk_pixbuf_fill (base_image, 0xFFFFFFFF);       /* white */
        g_tree_insert (SpacerTree, GINT_TO_POINTER (1024), base_image);
    }

    image = g_tree_lookup (SpacerTree, GINT_TO_POINTER (width_in_pixels));
    if (!image) {
        image =
            gdk_pixbuf_new_subpixbuf (base_image, 0, 0, width_in_pixels,
                                      1);
        g_tree_insert (SpacerTree, GINT_TO_POINTER (width_in_pixels),
                       image);
    }
    return image;
}
